package com.client.controller;

import com.client.service.IHelloTestService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.client.OAuth2AuthorizeRequest;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

/**
 * @author chengyadong
 * @date 2023/11/28 10:06
 * @description 测试类
 */
@RestController
@RequestMapping("/helloTest")
public class HelloTestController {
	@Autowired
	IHelloTestService helloTestService;

	@RequestMapping("/test")
	public String test(HttpServletRequest request) {
		return "client";
	}

	//查询数据库
	@RequestMapping("/query")
	public Map query(HttpServletRequest request) {
		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		Object principal = authentication.getPrincipal();
		System.out.println("登录信息：=" + principal);
		return helloTestService.query();
	}

	//查询数据库 SecurityContextHolder.getContext().getAuthentication()获取的为用户，权限信息，不包含token相关信息
	@RequestMapping("/query1")
	public Map query1(HttpServletRequest request, HttpServletResponse response) {
		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		Object principal = authentication.getPrincipal();
		System.out.println("登录信息：=" + principal);
		return helloTestService.query();
	}

	@PutMapping("/update")
	public Map update() {
		return helloTestService.update();
	}

	// 远程调用资源服务器  OAuth2AuthorizedClient中封装的是token信息不包含用户  如果使用@RegisteredOAuth2AuthorizedClient
	// OAuth2AuthorizedClient这种参数格式，再springFrameWork参数映射时其会帮我们判断OAuth2AuthorizedClient中的access_token是否过期，如果已过期其会帮我们远程调用
	// 授权服务器获取新的access_token,并且同步到内存和session中 所以只要用到该注解参数意味着access_token在调用资源服务器时永不过期
	@GetMapping("/queryByResource")
	public Map queryByResource(@RegisteredOAuth2AuthorizedClient OAuth2AuthorizedClient client) {
		//此处拿到的access_token都是有效的
		OAuth2AccessToken accessToken = client.getAccessToken();
		System.out.println("登录token:=" + accessToken);
		return helloTestService.queryByResource(client);
	}

	// 远程调用资源服务器--该方法无@RegisteredOAuth2AuthorizedClient OAuth2AuthorizedClient参数，不会判断access_token的有效性。
	// 当第一个请求到达客户端后其会去授权服务器进行认证授权，并且将认证结果(用户信息+token信息)存储到session中，这样当之后的请求再到达客户端后直接从session中获取
	// 就不会再访问授权服务器，客户端会拿着该内存或者session中的access_token直接去资源服务器，如果该token有效那么返回访问数据，
	// 如果token无效则返回401异常，此时需要我们捕获该异常，手动编写代码进行access_token的刷新，这就是令牌刷新模式
	@GetMapping("/queryByResource1")
	public Map queryByResource1(HttpServletRequest request,HttpServletResponse response) {
		String clientRegistrationId = "clientService";
		if (!StringUtils.hasLength(clientRegistrationId)) {
			throw new IllegalArgumentException("Unable to resolve the Client Registration Identifier. "
					+ "It must be provided via @RegisteredOAuth2AuthorizedClient(\"client1\") or "
					+ "@RegisteredOAuth2AuthorizedClient(registrationId = \"client1\").");
		}
		Authentication principal = SecurityContextHolder.getContext().getAuthentication();
		OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest
				.withClientRegistrationId(clientRegistrationId)
				.principal(principal)
				.attribute(HttpServletRequest.class.getName(), request)
				.attribute(HttpServletResponse.class.getName(), response)
				.build();
		OAuth2AuthorizedClient client = authorizeRequest.getAuthorizedClient();
		return helloTestService.queryByResource(client);
	}
}
